package com.jht.btconnect.ui;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ReceiverCallNotAllowedException;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.nfc.cardemulation.OffHostApduService;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.material.tabs.TabLayout;
import com.jht.btconnect.BTApp;
import com.jht.btconnect.R;
import com.jht.btconnect.adapter.BTDevicesFragmentPagerAdapter;
import com.jht.btconnect.common.AppPermission;
import com.jht.btconnect.common.AppUtil;
import com.jht.btconnect.common.DialogUtil;
import com.jht.btconnect.fragment.BTDeviceFragment;
import com.jht.btconnect.fragment.BTServicesFragment;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BTDevicesActivity extends BaseActivity implements View.OnClickListener {
    private final static String TAG = "BTDevicesActivity";
    //UI Widgets
    private LinearLayout mTopBar;
    private Button mBtnBack;
    private TextView mTvTitle;
    private Button mBtnCustomName;
    private LinearLayout mLlBtSwitch;
    private Button mBtnOpenBt;
    private LinearLayout mLlLocationSwitch;
    private Button mBtnOpenLocation;
    private TabLayout mTabLayout;
    private ViewPager mVpBtDevices;

    private BTDeviceFragment btDeviceFragment = null;
    private BTServicesFragment btServicesFragment = null;
    //Non UI Widgets
    private static final int RESULT_NOT_OK = 10;
    private static final int REQUEST_ENABLE_BT = 100;
    private static final int REQUEST_ENABLE_GPS = 101;
    private static final int REQUEST_PERMISSIONS = 103;
    //handler code
    public static final int UI_HIDE_BT_ENABLED = 200;
    public static final int UI_SHOW_BT_ENABLED = 201;
    public static final int UI_SHOW_OR_HIDE_GPS_ENABLED = 202;
    public static final int UI_DISMISS_DIALOG = 203;
    public static final int UI_GO_SETTINGS = 204;
    public static final int UI_DISCOVER_SERVICES = 205;
    public static final int UI_INIT_BT_SERVER_LV = 206;

    private boolean isBTOpen = false;
    private boolean isGPSOpen = false;
    private boolean hasAllPermissions = false;
    private boolean mScanning = false;
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothManager bluetoothManager;
    private UIHandler uiHandler = null;
    private BtAndGpsReceiver btAndGpsReceiver;
    private AlertDialog alertDialog;

    private String[] vp_titles = {"BT Devices" , "BT Services"};

    private BluetoothAdapter.LeScanCallback leScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi,
                                     byte[] scanRecord) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //Log.d(TAG, "run: device ==> " + device.getAddress());
                            btDeviceFragment.addDevice(device);
                        }
                    });
                }
            };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b_t_devices);
        Log.d(TAG, "onCreate: ");
        uiHandler = new UIHandler(this);
        btDeviceFragment = new BTDeviceFragment(uiHandler);
        btServicesFragment = new BTServicesFragment();
        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
        Log.d(TAG, "onCreate: bluetoothAdapter ==> " + bluetoothAdapter);
        isBTOpen = isBTOpen(bluetoothAdapter);
        isGPSOpen = isGPSOpen();
        initView();

        btAndGpsReceiver = new BtAndGpsReceiver();
        registerReceiver(btAndGpsReceiver, getFilters());

        hasAllPermissions = AppPermission.requestAppPermissions(this,REQUEST_PERMISSIONS);

    }

    private IntentFilter getFilters() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        return filter;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(btAndGpsReceiver);
    }

    private void initView() {
        mTopBar = findViewById(R.id.top_bar);
        mBtnBack = findViewById(R.id.btn_back);
        mTvTitle = findViewById(R.id.tv_title);
        mTvTitle.setText("BTDevices");
        mBtnCustomName = findViewById(R.id.btn_custom_name);
        mBtnCustomName.setText("Scan");
        mBtnCustomName.setOnClickListener(this);
        mLlBtSwitch = findViewById(R.id.ll_bt_switch);
        if (isBTOpen) {
            mLlBtSwitch.setVisibility(View.GONE);
        }
        mBtnOpenBt = findViewById(R.id.btn_open_bt);
        mBtnOpenBt.setOnClickListener(this);
        mLlLocationSwitch = findViewById(R.id.ll_location_switch);
        if (isGPSOpen) {
            mLlLocationSwitch.setVisibility(View.GONE);
        }
        mBtnOpenLocation = findViewById(R.id.btn_open_location);
        mBtnOpenLocation.setOnClickListener(this);

        mTabLayout = findViewById(R.id.tab_layout);
        mVpBtDevices = findViewById(R.id.vp_bt_devices);
        List<String> titles = initTitle();
        List<Fragment> fragments = initFragments();
        BTDevicesFragmentPagerAdapter btDevicesFragmentPagerAdapter = new BTDevicesFragmentPagerAdapter(getSupportFragmentManager(), titles, fragments);
        mVpBtDevices.setAdapter(btDevicesFragmentPagerAdapter);
        mTabLayout.setupWithViewPager(mVpBtDevices);

    }

    private List<Fragment> initFragments() {
        List<Fragment> fragmentList = new ArrayList<>();
        fragmentList.add(btDeviceFragment);
        fragmentList.add(btServicesFragment);
        return fragmentList;
    }

    private List<String> initTitle() {
        List<String> titles = new ArrayList<>();
        boolean b = Collections.addAll(titles, vp_titles);
        return titles;
    }

    private boolean isBTOpen(BluetoothAdapter btAdapter) {
        if (btAdapter == null || !btAdapter.isEnabled()) {
            return false;
        }
        return true;
    }

    private boolean isGPSOpen() {
        LocationManager locationManager = (LocationManager) (BTApp.getAppContext()).getSystemService(Context.LOCATION_SERVICE);
        boolean gpsLocation = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        boolean networkLocation = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        if (gpsLocation || networkLocation) {
            return true;
        }
        return false;
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.btn_custom_name:
                hasAllPermissions = AppPermission.requestAppPermissions(this,REQUEST_PERMISSIONS);
                if (hasAllPermissions && isBTOpen && isGPSOpen){
                    Log.d(TAG, "onClick: start scan！！！！");
                    btDeviceFragment.initDevice();
                    startScan();
                }
                Log.d(TAG, "onClick: R.id.btn_custom_name ==> hasAllPermissions =" + hasAllPermissions
                        + " ; isBTOpen = " + isBTOpen + " ; isGPSOpen = " + isGPSOpen
                );
                break;
            case R.id.btn_open_bt:
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
                break;
            case R.id.btn_open_location:
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivityForResult(intent, REQUEST_ENABLE_GPS);
                break;
        }

    }

    private void startScan(){
        if (mScanning){

        } else {
            mScanning = true;
            bluetoothAdapter.startLeScan(leScanCallback);
            uiHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    bluetoothAdapter.stopLeScan(leScanCallback);
                    Toast.makeText(BTApp.getAppContext(),"BT scan is ok!",Toast.LENGTH_SHORT).show();
                }
            }, 1000 * 3 * 10);
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
            case REQUEST_ENABLE_GPS:
                uiHandler.sendEmptyMessage(UI_SHOW_OR_HIDE_GPS_ENABLED);
                break;
            case REQUEST_ENABLE_BT:
                if (resultCode == RESULT_OK) {
                    uiHandler.sendEmptyMessage(UI_HIDE_BT_ENABLED);
                }
                break;
        }

    }

    public void openBT(int resultCode) {
        if (resultCode == RESULT_OK) {
            isBTOpen = true;
        } else {
            isBTOpen = false;
        }
        if (isBTOpen) {
            mLlBtSwitch.setVisibility(View.GONE);
        } else {
            mLlBtSwitch.setVisibility(View.VISIBLE);
        }
    }

    public void openGPS() {
        isGPSOpen = isGPSOpen();
        if (isGPSOpen) {
            mLlLocationSwitch.setVisibility(View.GONE);
        } else {
            mLlLocationSwitch.setVisibility(View.VISIBLE);
        }
    }

    public void updateFragmentService(List<BluetoothGattService> services){
        btServicesFragment.addBTServices(services);
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_PERMISSIONS: {
                if (grantResults.length > 0) {
                    String permissionsMsg = "please grant permission { ";
                    boolean grantResultsOK = true;
                    boolean shouldShowRequestPermission = false;
                    for (int i = 0; i < grantResults.length; i++){
                        if (grantResults[i] != PackageManager.PERMISSION_GRANTED){
                            grantResultsOK = false;
                            if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
                                    permissions[i])){
                                shouldShowRequestPermission = true;
                                permissionsMsg += "'" + permissions[i] + "'";
                            }
                        }
                    }
                    hasAllPermissions = grantResultsOK;
                    permissionsMsg += " }";
                    if (shouldShowRequestPermission){
                        alertDialog = DialogUtil.showMsgAlertDialog(this,permissionsMsg,uiHandler);
                        alertDialog.show();
                    }

                } else {
                    hasAllPermissions = false;
                }
                return;
            }
        }
    }


    public static class UIHandler extends Handler {
        private WeakReference<BTDevicesActivity> ref = null;

        public UIHandler(BTDevicesActivity btDevicesActivity) {
            ref = new WeakReference<BTDevicesActivity>(btDevicesActivity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            BTDevicesActivity btDevicesActivity = ref.get();
            switch (msg.what) {
                case UI_HIDE_BT_ENABLED:
                    btDevicesActivity.openBT(RESULT_OK);
                    break;
                case UI_SHOW_BT_ENABLED:
                    btDevicesActivity.openBT(RESULT_NOT_OK);
                    break;
                case UI_SHOW_OR_HIDE_GPS_ENABLED:
                    btDevicesActivity.openGPS();
                    break;
                case UI_DISMISS_DIALOG:
                    btDevicesActivity.hideDialog();
                    break;
                case UI_GO_SETTINGS:
                    btDevicesActivity.goSettingUI();
                    break;
                case UI_DISCOVER_SERVICES:
                    Bundle data = msg.getData();
                    List<Parcelable> bt_services = data.getParcelableArrayList("bt_services");
                    ArrayList<BluetoothGattService> services = new ArrayList<>();
                    if (bt_services == null){
                        Log.d(TAG, "handleMessage: bt_services == null");
                        return;
                    }
                    for (Parcelable p : bt_services){
                        services.add((BluetoothGattService)p);
                    }
                    btDevicesActivity.updateFragmentService(services);
                    break;
                case UI_INIT_BT_SERVER_LV:
                    Log.d(TAG, "handleMessage: clear data!!");
                    btDevicesActivity.clearData();
                    break;
            }

        }

    }

    private void clearData() {
        btServicesFragment.clearData();
    }

    private void hideDialog() {
        if (alertDialog != null){
            alertDialog.dismiss();
        }
    }

    public void goSettingUI(){
        AppUtil.launchSettingUI(BTApp.getAppContext());
    }


    private class BtAndGpsReceiver extends BroadcastReceiver {
        /**
         * int STATE_OFF = 10; //bt closed
         * int STATE_ON = 12; //bt opened
         * int STATE_TURNING_OFF = 13; //bt is closing
         * int STATE_TURNING_ON = 11; //bt is opening
         *
         * @param context
         * @param intent
         */
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "onReceive: action == >" + action);
            if (LocationManager.PROVIDERS_CHANGED_ACTION.equals(action)) {
                uiHandler.sendEmptyMessage(UI_SHOW_OR_HIDE_GPS_ENABLED);
            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
                Log.d(TAG, "onReceive: state ==> " + state);
                if (state == BluetoothAdapter.STATE_OFF || state == BluetoothAdapter.STATE_TURNING_OFF) {
                    uiHandler.sendEmptyMessage(UI_SHOW_BT_ENABLED);
                } else {
                    uiHandler.sendEmptyMessage(UI_HIDE_BT_ENABLED);
                }
            }

        }

    }



}
